/**
 * 
 */
package com.witframework.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Hashtable;

/**
 * @author wuxinyang
 * Oct 19, 2009 10:30:35 AM
 * 
 */
class URLClassLoader extends ClassLoader {
	  Hashtable cache = new Hashtable();
	  URL url;

	  public URLClassLoader(URL u) {
	    this.url = u;
	  }

	  public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
	    Class cls = (Class) cache.get(name);
	    if (cls == null) {
	      try {
	        cls = findSystemClass(name);
	      } catch (ClassNotFoundException e) {
	      }
	    }
	    if (cls == null) {
	      byte classData[] = loadClassData(name);
	      cls = defineClass(classData, 0, classData.length);
	      cache.put(name, cls);
	    }
	    if (resolve) {
	      resolveClass(cls);
	    }
	    return cls;
	  }
	  private byte[] loadClassData(String name) throws ClassNotFoundException {
	    byte[] buffer;
	    InputStream theClassInputStream = null;
	    int bufferLength = 128;
	    try {
	      URL classURL = new URL(url, name + ".class");
	      URLConnection uc = classURL.openConnection();
	      uc.setAllowUserInteraction(false);

	      try {
	        theClassInputStream = uc.getInputStream();
	      } catch (NullPointerException e) {
	        System.err.println(e);
	        throw new ClassNotFoundException(name + " input stream problem");
	      }
	      int contentLength = uc.getContentLength();

	      // A lot of web servers don't send content-lengths
	      // for .class files
	      if (contentLength == -1) {
	        buffer = new byte[bufferLength * 16];
	      } else {
	        buffer = new byte[contentLength];
	      }

	      int bytesRead = 0;
	      int offset = 0;

	      while (bytesRead >= 0) {
	        bytesRead = theClassInputStream.read(buffer, offset, bufferLength);
	        if (bytesRead == -1)
	          break;
	        offset += bytesRead;
	        if (contentLength == -1 && offset == buffer.length) { // grow the array
	          byte temp[] = new byte[offset * 2];
	          System.arraycopy(buffer, 0, temp, 0, offset);
	          buffer = temp;
	        } else if (offset > buffer.length) {
	          throw new ClassNotFoundException(name + " error reading data into the array");
	        }
	      }

	      if (offset < buffer.length) { // shrink the array
	        byte temp[] = new byte[offset];
	        System.arraycopy(buffer, 0, temp, 0, offset);
	        buffer = temp;
	      }

	      // Make sure all the bytes were received
	      if (contentLength != -1 && offset != contentLength) {
	        throw new ClassNotFoundException("Only " + offset + " bytes received for " + name
	            + "\n Expected " + contentLength + " bytes");
	      }
	    } catch (Exception e) {
	      throw new ClassNotFoundException(name + " " + e);
	    } finally {
	      try {
	        if (theClassInputStream != null)
	          theClassInputStream.close();
	      } catch (IOException e) {
	      }
	    }
	    return buffer;
	  }
	}
